//@ts-nocheck
import React, {MutableRefObject, useRef, RefObject, useEffect, useState, ReactNode} from 'react';
import {Progress,Icon} from 'antd';
import './index.css'

//type PropsWithChildren<P> = P & { children?: ReactNode }; // 帮我们自动添加children
export type DraggerProps = React.PropsWithChildren<{
    onChange: any;
    name: string;
    action: string;
}>


export interface UploadFile {
    file?: File; //上传的文件
    percent?: number; //当前文件上传的百分比
    url?: string; //服务器上传成功之后返回的访问URL地址
    status?: string; //状态  initial uploading error done
}

const Dragger: React.FunctionComponent<DraggerProps> = function (props: DraggerProps): React.ReactElement {
  const [uploadFiles, setUploadFiles] = useState<Array<UploadFile>>([]);

  //TODO 第一次渲染current=undefined(此时还没有拿到dom
  //，第二次渲染开始 current指向真实dom元素
  //，从第二次开始指向就不再改变
  //故说ref是个可变对象，但在整个生命周期内不变
  const uploadContainer: MutableRefObject<HTMLDivElement | undefined> = useRef<HTMLDivElement | undefined>();

  const onDragEnter: (ev: DragEvent) => any = (ev: DragEvent): any => { //进入
    console.log('onDragEnter');
    ev.preventDefault(); //要阻止默认事件 否则会直接打开文件
  };

  const onDragOver: (ev: DragEvent) => any = (ev: DragEvent): any => { //在目标内移动
    console.log('onDragOver');
    ev.preventDefault(); //要阻止默认事件 否则会直接打开文件
    ev.stopPropagation();
  };

  const onDragLeave: (ev: DragEvent) => any = (ev: DragEvent): any => {//离开目标
    console.log('onDragLeave');
    ev.preventDefault(); //要阻止默认事件 否则会直接打开文件
  };

  const onDragDrop: (ev: DragEvent) => any = (ev: DragEvent): any => {//松手
    console.log('onDragDrop');
    ev.preventDefault(); //要阻止默认事件 否则会直接打开文件
    ev.stopPropagation();
    const transfer: DataTransfer | null = ev.dataTransfer; //这个属性下有我们拖动的文件
    if (transfer && transfer.files) {
      upload(transfer.files);
    }
  };

  function upload(files: FileList){
    console.log('files:', files);
    /*
            FileList {0: File, length: 1}
            0: File
                lastModified: 1573352693014
                lastModifiedDate: Sun Nov 10 2019 10:24:53 GMT+0800 (中国标准时间) {}
                name: "README.md"
                size: 2155
                type: ""
                webkitRelativePath: ""
                __proto__: File
            length: 1
            __proto__: FileList
        */
    for(let i = 0;i<files.length;++i){
      const file = files[i];
      const formData = new FormData();
      formData.append('filename', file.name);
      formData.append(props.name, file);
      const xhr: XMLHttpRequest = new XMLHttpRequest();
      xhr.open('POST', props.action, true);
      xhr.responseType = 'json';
      const uploadFile: UploadFile = {file, percent: 0, status: 'uploading', url:''};
      uploadFiles.push(uploadFile);

      xhr.onprogress = onUploadProgress(uploadFile);
      xhr.upload.onprogress = onUploadProgress(uploadFile);

      // @ts-ignore
      // xhr.onprogress = onUploadProgress;
      // @ts-ignore
      // xhr.upload.onprogress = onUploadProgress;
      // @ts-ignore
      /*function onUploadProgress(event:ProgressEvent) {
                if(event.lengthComputable){
                    const percent = parseInt((event.loaded / event.total * 100).toFixed(0));
                    uploadFile.percent = percent;
                    if(percent >= 100){
                        uploadFile.status = 'done';
                    }
                    setUploadFiles([...uploadFiles]);
                }
            }*/

      xhr.onerror = function () {
        uploadFile.status = 'error';
        setUploadFiles([...uploadFiles]); //TODO ←emmm 这里写错了 应该应该循环找到是哪个uploadFile错了 然后替换掉 再整体...
      };

      xhr.onreadystatechange = function () {
        if (xhr.readyState === 4 && xhr.status === 200) {
          uploadFile.url = xhr.response.url; //图片上传后返回的url地址
          props.onChange(uploadFile);
        }
      };

      xhr.send(formData);
    }

    function onUploadProgress(uploadFile: UploadFile) {
      return (event: ProgressEvent)=>{
        if(event.lengthComputable){
          /*https://www.cnblogs.com/AlphaThink-AT003/p/5715408.html?utm_source=itdadao&utm_medium=referral
                        在服务器端注意附加 “Content-Length”和Content-Encoding
                        ，这样 JS 端的 progress 事件的 event.lengthComputable 值才会为 true
                        ， event.total 才会在数据传输完毕之前取得值
                        ，否则 event.lengthComputable 值会返回 false， event.total 在数据完成之前值都是0。
                    */
          const percent = parseInt((event.loaded / event.total * 100).toFixed(0));
          uploadFile.percent = percent;
          if(percent >= 100){
            uploadFile.status = 'done';
          }
          setUploadFiles([...uploadFiles]);
        }
      }
    }
  }

  //useEffect中的函数会在组件挂载完成即真实DOM挂载完成后执行 或则 更新完成后执行
  useEffect(() => {
        uploadContainer.current!.addEventListener('dragenter', onDragEnter);
        uploadContainer.current!.addEventListener('dragover', onDragOver);
        uploadContainer.current!.addEventListener('dragleave', onDragLeave);
        uploadContainer.current!.addEventListener('drop', onDragDrop);

        return ()=>{ //useEffect返回一个函数，它会在组件卸载时执行
            uploadContainer.current!.removeEventListener('dragenter', onDragEnter);
            uploadContainer.current!.removeEventListener('dragover', onDragOver);
            uploadContainer.current!.removeEventListener('dragleave', onDragLeave);
            uploadContainer.current!.removeEventListener('drop', onDragDrop);
        }
  },[]/*空数组,没有依赖,表示只会执行一次；如果省略这个参数这是每次都会执行*/);

  console.log('render uploadFiles:',uploadFiles);
  return (
    <>
      <div className="dragger-container" ref={uploadContainer as RefObject<HTMLDivElement> | null}>
        {props.children}
      </div>
      {
        uploadFiles.map((uploadFile: UploadFile, index: number) => (
          <div key={index}>
            <div>
              {uploadFile.status === 'loading' ? <Icon type="loading"/> : <Icon type="paper-clip"/>}
              <span style={{marginLeft: 10}}>{uploadFile.file!.name}</span>
            </div>
            <Progress percent={uploadFile.percent} status={uploadFile.status === 'error' ? 'exception' : undefined}/>
          </div>
        ))
      }
    </>
  );
};

export default Dragger;
